Buka kekuatan useRef di React. Jelajahi berbagai kasus penggunaan, termasuk akses DOM langsung, menjaga nilai yang dapat berubah, dan mengoptimalkan komponen fungsional.
React useRef: Menguasai Pola Penyimpanan Nilai yang Dapat Berubah
useRef adalah hook yang kuat di React yang menyediakan cara untuk menyimpan nilai di antara render tanpa menyebabkan render ulang saat nilai tersebut berubah. Hook ini sering dikaitkan dengan mengakses elemen DOM secara langsung, tetapi kemampuannya jauh lebih dari itu. Panduan komprehensif ini akan mendalami berbagai kasus penggunaan useRef, memberdayakan Anda untuk menulis kode React yang lebih efisien dan mudah dipelihara.
Memahami useRef: Lebih dari Sekadar Akses DOM
Pada dasarnya, useRef mengembalikan objek ref yang dapat berubah (mutable) yang properti .current-nya diinisialisasi dengan argumen yang diberikan (initialValue). Objek yang dikembalikan akan bertahan selama siklus hidup penuh komponen. Yang terpenting, memodifikasi properti .current tidak memicu render ulang. Inilah perbedaan utama antara useRef dan useState.
Meskipun mengakses elemen DOM adalah kasus penggunaan yang umum, useRef unggul dalam mengelola nilai apa pun yang dapat berubah yang tidak perlu menyebabkan render ulang saat diperbarui. Ini membuatnya sangat berharga untuk tugas-tugas seperti:
- Menyimpan nilai prop atau state sebelumnya.
- Mempertahankan penghitung atau pewaktu.
- Melacak status fokus tanpa menyebabkan render ulang.
- Menyimpan nilai apa pun yang dapat berubah yang perlu dipertahankan di seluruh render.
Penggunaan Dasar: Mengakses Elemen DOM
Kasus penggunaan yang paling terkenal adalah mengakses elemen DOM secara langsung. Ini berguna untuk skenario di mana Anda perlu berinteraksi secara imperatif dengan node DOM, seperti memberi fokus pada bidang input, mengukur dimensinya, atau memicu animasi.
Contoh: Memberi Fokus pada Bidang Input
Berikut cara menggunakan useRef untuk memberi fokus pada bidang input saat komponen dipasang (mount):
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
// Focus the input field on mount
if (inputRef.current) {
inputRef.current.focus();
}
}, []); // Empty dependency array ensures this runs only once on mount
return (
<input type="text" ref={inputRef} placeholder="Enter text" />
);
}
export default MyComponent;
Penjelasan:
- Kita membuat sebuah ref menggunakan
useRef(null). Nilai awalnya adalahnullkarena elemen input belum ada saat komponen pertama kali dirender. - Kita melampirkan ref ke elemen input menggunakan prop
ref:ref={inputRef}. React akan secara otomatis mengaturinputRef.currentke node DOM saat elemen input dipasang. - Kita menggunakan
useEffectdengan array dependensi kosong ([]) untuk memastikan efek hanya berjalan sekali setelah komponen dipasang. - Di dalam efek, kita memeriksa apakah
inputRef.currentada (untuk menghindari kesalahan jika elemen belum tersedia) lalu memanggilinputRef.current.focus()untuk memberi fokus pada bidang input.
Lebih Jauh dari Akses DOM: Mengelola Nilai yang Dapat Berubah
Kekuatan sebenarnya dari useRef terletak pada kemampuannya untuk menyimpan nilai yang dapat berubah yang bertahan di seluruh render tanpa memicu render ulang. Ini membuka berbagai kemungkinan untuk mengoptimalkan perilaku komponen dan mengelola state dalam komponen fungsional.
Contoh: Menyimpan Nilai Prop atau State Sebelumnya
Terkadang, Anda perlu mengakses nilai sebelumnya dari sebuah prop atau variabel state. useRef menyediakan cara yang bersih untuk melakukan ini tanpa memicu render ulang yang tidak perlu.
import React, { useRef, useEffect } from 'react';
function MyComponent({ value }) {
const previousValue = useRef(value);
useEffect(() => {
// Update the ref's .current property with the current value
previousValue.current = value;
}, [value]); // Effect runs whenever the 'value' prop changes
// Now you can access the previous value using previousValue.current
return (
<div>
Current value: {value}
<br />
Previous value: {previousValue.current}
</div>
);
}
export default MyComponent;
Penjelasan:
- Kita menginisialisasi ref
previousValuedengan nilai awal dari propvalue. - Kita menggunakan
useEffectuntuk memperbarui propertipreviousValue.currentsetiap kali propvalueberubah. - Di dalam komponen, kita sekarang dapat mengakses nilai sebelumnya dari prop
valuemenggunakanpreviousValue.current.
Contoh Kasus Penggunaan: Melacak Perubahan dalam Respons API (Skenario Internasional)
Bayangkan Anda sedang membangun dasbor yang menampilkan nilai tukar mata uang yang diambil dari API. API tersebut mungkin mengembalikan nilai tukar dalam format yang berbeda atau dengan tingkat presisi yang bervariasi tergantung pada sumber datanya (misalnya, API Bank Sentral Eropa vs. API lembaga keuangan Asia Tenggara). Anda dapat menggunakan useRef untuk melacak nilai tukar sebelumnya dan menampilkan indikator visual (misalnya, panah hijau ke atas atau panah merah ke bawah) untuk menunjukkan apakah nilai tukar telah meningkat atau menurun sejak pembaruan terakhir. Ini sangat penting bagi pengguna internasional yang mengandalkan nilai tukar ini untuk keputusan keuangan.
Contoh: Mempertahankan Penghitung atau Pewaktu
useRef sangat cocok untuk mengelola penghitung atau pewaktu yang tidak perlu memicu render ulang. Misalnya, Anda mungkin menggunakannya untuk melacak berapa kali sebuah tombol telah diklik atau untuk mengimplementasikan pewaktu sederhana.
import React, { useRef, useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const clickCount = useRef(0); // Initialize the ref with 0
const handleClick = () => {
clickCount.current++; // Increment the ref's .current property
setCount(clickCount.current); //Increment state which re-renders.
};
return (
<div>
<p>Button clicked: {count} times</p>
<button onClick={handleClick}>Click me</button>
</div>
);
}
export default MyComponent;
Penjelasan:
- Kita menginisialisasi sebuah ref
clickCountdengan nilai 0. - Dalam fungsi
handleClick, kita menaikkan nilai properticlickCount.current. Ini tidak memicu render ulang. - Kita juga memperbarui state 'count' yang memicu render ulang.
Contoh: Menerapkan Fungsi Debounce
Debouncing adalah teknik yang digunakan untuk membatasi laju eksekusi sebuah fungsi. Ini biasanya digunakan dalam bidang input pencarian untuk mencegah panggilan API yang berlebihan saat pengguna sedang mengetik. useRef dapat digunakan untuk menyimpan ID pewaktu yang digunakan dalam fungsi debounce.
import React, { useState, useRef, useEffect } from 'react';
function MyComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const timerRef = useRef(null); // Store the timer ID
const handleChange = (event) => {
const newSearchTerm = event.target.value;
setSearchTerm(newSearchTerm);
// Clear the previous timer if it exists
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// Set a new timer
timerRef.current = setTimeout(() => {
// Simulate an API call
fetch(`https://api.example.com/search?q=${newSearchTerm}`)
.then(response => response.json())
.then(data => setResults(data.results));
}, 300); // Debounce for 300 milliseconds
};
return (
<div>
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={handleChange}
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.name}</li>
))}
</ul>
</div>
);
}
export default MyComponent;
Penjelasan:
- Kita menggunakan
useRefuntuk menyimpan ID pewaktu ditimerRef. - Dalam fungsi
handleChange, kita membersihkan pewaktu sebelumnya (jika ada) menggunakanclearTimeout(timerRef.current). - Kita kemudian mengatur pewaktu baru menggunakan
setTimeoutdan menyimpan ID pewaktu ditimerRef.current. - Panggilan API hanya dilakukan setelah pengguna berhenti mengetik selama 300 milidetik.
Pertimbangan Internasionalisasi: Saat menerapkan debouncing dengan panggilan API yang melibatkan tampilan informasi dalam berbagai bahasa, pastikan API Anda mendukung internasionalisasi dan mengembalikan data dalam bahasa pilihan pengguna. Pertimbangkan untuk menggunakan header Accept-Language dalam permintaan API Anda.
Contoh: Melacak Status Fokus tanpa Render Ulang
Anda dapat menggunakan useRef untuk melacak apakah sebuah elemen memiliki fokus tanpa menyebabkan render ulang. Ini bisa berguna untuk menata gaya elemen berdasarkan status fokusnya atau untuk menerapkan logika manajemen fokus kustom.
import React, { useRef, useState } from 'react';
function MyComponent() {
const [isFocused, setIsFocused] = useState(false);
const inputRef = useRef(null);
const handleFocus = () => {
setIsFocused(true);
};
const handleBlur = () => {
setIsFocused(false);
};
return (
<div>
<input
type="text"
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<p>Input is focused: {isFocused ? 'Yes' : 'No'}</p>
</div>
);
}
export default MyComponent;
useRef vs. useState: Memilih Alat yang Tepat
Penting untuk memahami perbedaan utama antara useRef dan useState untuk memilih alat yang tepat untuk pekerjaan tersebut.
| Fitur | useRef | useState |
|---|---|---|
| Memicu Render Ulang | Tidak | Ya |
| Tujuan | Menyimpan nilai yang dapat berubah yang tidak perlu memicu render ulang. Mengakses elemen DOM. | Mengelola state yang perlu memicu render ulang. |
| Persistensi | Bertahan di seluruh render ulang. | Bertahan di seluruh render ulang, tetapi nilainya diperbarui menggunakan fungsi setter. |
Praktik Terbaik dan Kesalahan Umum
- Jangan memutasi state secara langsung: Meskipun
useRefmemungkinkan Anda untuk memutasi nilai secara langsung, hindari memutasi variabel state yang dikelola olehuseStatesecara langsung. Selalu gunakan fungsi setter yang disediakan olehuseStateuntuk memperbarui state. - Waspadai efek samping: Saat menggunakan
useRefuntuk mengelola nilai yang memengaruhi UI, waspadai potensi efek samping. Pastikan kode Anda berperilaku dapat diprediksi dan tidak menimbulkan bug yang tidak terduga. - Jangan mengandalkan
useRefuntuk logika rendering: Karena perubahanuseReftidak memicu render ulang, jangan mengandalkan nilainya secara langsung untuk menentukan apa yang harus dirender. GunakanuseStateuntuk nilai yang perlu mendorong logika rendering. - Pertimbangkan implikasi performa: Meskipun
useRefdapat membantu mengoptimalkan performa dengan mencegah render ulang yang tidak perlu, sadarilah bahwa penggunaan nilai yang dapat berubah secara berlebihan dapat membuat kode Anda lebih sulit untuk dipahami dan di-debug.
Kasus Penggunaan dan Pola Lanjutan
Mempertahankan Nilai di Seluruh Instans Komponen
Meskipun `useRef` mempertahankan nilai di seluruh render dari *satu* instans komponen, terkadang Anda memerlukan nilai untuk bertahan di *berbagai* instans dari komponen yang sama. Ini memerlukan pendekatan yang sedikit berbeda, sering kali memanfaatkan variabel tingkat modul yang dikombinasikan dengan `useRef`.
// myComponent.js
let globalCounter = 0; // Module-level variable
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const counterRef = useRef(globalCounter); // Initialize with the global value
useEffect(() => {
// Update the global counter whenever the ref changes
globalCounter = counterRef.current;
}, [counterRef.current]);
const increment = () => {
counterRef.current++;
//No setState needed, so no re-render
};
return (
<div>
<p>Counter: {counterRef.current}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default MyComponent;
Pertimbangan Penting: Pola ini memperkenalkan variabel global, jadi berhati-hatilah terhadap potensi efek samping dan kondisi persaingan (race conditions), terutama dalam aplikasi yang kompleks. Pertimbangkan pendekatan alternatif seperti menggunakan penyedia konteks (context provider) jika nilai tersebut perlu dibagikan di antara beberapa komponen dengan cara yang lebih terkontrol.
Kesimpulan: Melepaskan Kekuatan useRef
useRef adalah alat serbaguna di React yang jauh melampaui sekadar mengakses elemen DOM. Dengan memahami kemampuannya untuk menyimpan nilai yang dapat berubah tanpa memicu render ulang, Anda dapat mengoptimalkan komponen Anda, mengelola state dengan lebih efektif, dan membangun aplikasi React yang lebih berkinerja dan mudah dipelihara. Ingatlah untuk menggunakannya dengan bijaksana dan selalu mempertimbangkan potensi pertukaran antara performa dan kejelasan kode.
Dengan menguasai pola-pola yang dijelaskan dalam panduan ini, Anda akan siap untuk memanfaatkan potensi penuh useRef dalam proyek React Anda, baik saat membangun aplikasi web sederhana maupun sistem perusahaan yang kompleks. Ingatlah untuk mempertimbangkan internasionalisasi dan aksesibilitas saat membangun untuk audiens global!